import time
import json
from fastapi import Request, Response
from src.utils.logger import get_logger
from urllib.parse import unquote
logger = get_logger("capcut")


async def SimpleLoggingMiddleware(request: Request, call_next):
    start_time = time.time()

    # 获取请求信息
    request_info = await get_request_info(request)
    logger.info(f"→ {request_info}")

    # 调用下一个中间件或路由
    response = await call_next(request)

    process_time = time.time() - start_time

    # 获取响应信息
    response_info = await get_response_info(response, process_time, request.method, request.url.path)
    logger.info(f"← {response_info}")

    return response


async def get_request_info(request: Request) -> str:
    """获取请求详细信息"""
    method = request.method
    path = unquote(str(request.url))
    client_ip = request.client.host if request.client else "unknown"

    info_parts = [f"{method} {path}"]

    # 添加查询参数
    if request.query_params:
        query_params = dict(request.query_params)
        info_parts.append(f"query={json.dumps(query_params, ensure_ascii=False)}")

    # 添加请求体
    if method in ["POST", "PUT", "PATCH", "DELETE"]:
        body_info = await get_request_body_info(request)
        if body_info:
            info_parts.append(body_info)

    info_parts.append(f"client={client_ip}")
    return " | ".join(info_parts)


async def get_request_body_info(request: Request) -> str:
    """获取请求体信息"""
    try:
        body_bytes = await request.body()

        # 将body放回，否则后续中间件无法读取
        async def receive():
            return {"type": "http.request", "body": body_bytes}

        request._receive = receive

        if not body_bytes:
            return None

        content_type = request.headers.get("content-type", "")
        if "application/json" in content_type:
            try:
                body = json.loads(body_bytes.decode('utf-8'))
                body_str = json.dumps(body, ensure_ascii=False)
                if len(body_str) > 500:
                    body_str = body_str[:500] + "...[truncated]"
                return f"body={body_str}"
            except:
                pass

        body_preview = body_bytes.decode('utf-8', errors='ignore')[:200]
        if len(body_bytes) > 200:
            body_preview += "...[truncated]"
        return f"body_preview={body_preview}"

    except Exception:
        return None


async def get_response_info(response: Response, process_time: float, method: str, path: str) -> str:
    """获取响应详细信息"""
    info_parts = [
        f"{method} {path}",
        f"status={response.status_code}",
        f"time={process_time:.3f}s"
    ]

    # 获取响应体信息
    response_body_info = await get_response_body_info(response)
    if response_body_info:
        info_parts.append(response_body_info)

    return " | ".join(info_parts)


async def get_response_body_info(response: Response) -> str:
    """获取 StreamingResponse 的响应体信息"""
    try:
        # 检查是否是流式响应
        if hasattr(response, "body_iterator"):
            # 收集响应体 chunks
            body_chunks = []
            async for chunk in response.body_iterator:
                body_chunks.append(chunk)

            # 重新构建响应体迭代器
            response.body_iterator = async_iterator(body_chunks)

            # 合并所有 chunks
            full_body = b''.join(body_chunks)

            if not full_body:
                return None

            # 检查是否为 JSON 响应
            content_type = response.headers.get("content-type", "")
            if "application/json" in content_type:
                try:
                    body_json = json.loads(full_body.decode('utf-8'))
                    body_str = json.dumps(body_json, ensure_ascii=False)
                    if len(body_str) > 500:
                        body_str = body_str[:500] + "...[truncated]"
                    return f"response={body_str}"
                except json.JSONDecodeError:
                    # 如果不是有效的 JSON，显示原始文本预览
                    body_preview = full_body.decode('utf-8', errors='ignore')[:200]
                    if len(full_body) > 200:
                        body_preview += "...[truncated]"
                    return f"response_preview={body_preview}"

            # 非 JSON 响应
            # body_preview = full_body.decode('utf-8', errors='ignore')[:200]
            # if len(full_body) > 200:
            #     body_preview += "...[truncated]"
            # return f"response_preview={body_preview}"

        # 对于非流式响应
        # elif hasattr(response, "body") and response.body:
        #     body = response.body
        #     if isinstance(body, bytes):
        #         content_type = response.headers.get("content-type", "")
        #         if "application/json" in content_type:
        #             try:
        #                 body_json = json.loads(body.decode('utf-8'))
        #                 body_str = json.dumps(body_json, ensure_ascii=False)
        #                 if len(body_str) > 500:
        #                     body_str = body_str[:500] + "...[truncated]"
        #                 return f"response={body_str}"
        #             except:
        #                 pass
        #
        #         body_preview = body.decode('utf-8', errors='ignore')[:200]
        #         if len(body) > 200:
        #             body_preview += "...[truncated]"
        #         return f"response_preview={body_preview}"

        return None

    except Exception as e:
        # 记录错误但不中断请求
        logger.warning(f"获取响应体信息失败: {str(e)}")
        return None


async def async_iterator(chunks):
    """将 chunks 列表转换为异步迭代器"""
    for chunk in chunks:
        yield chunk